﻿using System;
using System.Collections.Generic;
using System.Text;

using SchEdu.Framework.Algorithm;
using SchEdu.Framework.DataModel;
using SchEdu.Framework.Exceptions;
using SchEdu.Framework.Validators;


namespace SchEdu.Framework.Algorithm
{
    public abstract class LawlerAlgorithm : Algorithm
    {
        public LawlerAlgorithm()
            : base()
        {
        }

        public LawlerAlgorithm(SchEduData schEduData)
            : base(schEduData)
        {
        }

        protected override void InitializeValidators()
        {
            base.InitializeValidators();

            validators.Add(new OrderValidator(SchEduData));
            validators.Add(new OrderDueDateValidator(SchEduData));
            validators.Add(new OrderProcessingTimeValidator(SchEduData));
            validators.Add(new WorkCenterValidator(SchEduData, 1, 1));
            validators.Add(new OperationPerOrderValidator(SchEduData, 1, 1));
        }


        protected override void Logic()
        {
            SchEduDataSet.WorkCenterRow workCenter = SchEduData.WorkCenter[0];
            SchEduDataSet.MachineRow machine = SchEduData.Machine[0];

            OperationList operationsOut = new OperationList();
            int completionTime = Operations.ProcessingTime();

            while (Operations.Count > 0)
            {
                OperationList operationWithoutSuccessors = new OperationList();
                OperationList operationWithMinCost = new OperationList();
                foreach (SchEduDataSet.OperationRow operation in Operations)
                {
                    if (Dependencies.HasSuccessor(operation.OrderRow) == true)
                    {
                        continue;
                    }
                    operationWithoutSuccessors.Add(operation);
                }
                if (operationWithoutSuccessors.Count == 0)
                {
                    throw new AlgorithmException(Resources.NoFeasibleSolution);
                }

                while (operationWithoutSuccessors.Count > 0)
                {
                    int lowestCost = Int32.MaxValue;
                    SchEduDataSet.OperationRow nextOperation = null;
                    foreach (SchEduDataSet.OperationRow op in operationWithoutSuccessors)
                    {
                        int cost = GetCost(op.OrderRow, completionTime);
                        if (cost < lowestCost)
                        {
                            lowestCost = cost;
                            nextOperation = op;
                        }
                    }

                    operationsOut.Insert(0, nextOperation);
                    nextOperation.WorkCenterID = workCenter.ID;
                    nextOperation.MachineID = machine.ID;
                    operationWithoutSuccessors.Remove(nextOperation);
                    Operations.Remove(nextOperation);
                    Dependencies.RemoveOrder(nextOperation.OrderRow);
                    completionTime = completionTime - nextOperation.ProcessingTime;
                }

            }

            foreach (SchEduDataSet.OperationRow operation in operationsOut)
            {
                operation.StartDate = time;
                time = time + operation.ProcessingTime;
                operation.EndDate = time - 1;
            }

            Operations.Clear();
            Operations.AddRange(operationsOut);

        }

        protected abstract int GetCost(SchEduDataSet.OrderRow order, int completionTime);

        public abstract override AboutInfo AboutInfo
        {
            get;
        }

    }
}
